//FUNCTION:模拟PC与xs5013通讯的流程。

#include <stdio.h>
#include <windows.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>

//#include <termios.h> //mgwin 不支持该头文件

#include "ahdData.h"

#define BAUDRATE B115200

#if 0  //mgwin不支持termios.h, 只能调用windows的api
int OpenPcUart(int u32PortNum)
{
    char strDevName[8];
    int fd = -1;
    
    memset(strDevName, 0, sizeof(strDevName));
    snprintf(strDevName, 8, "COM%d", u32PortNum);
    strDevName[7] = '\0';

    fd = open(strDevName, O_RDWR | O_NOCTTY | O_NDELAY);
    if (fd == -1)
    {
        printf("Open com3 err(%s)!\n", strerror(errno));

    } else {
        printf("Open com3(%d) success!\n", fd);
    }

    return fd;
}

int PcUartInit(int fd)
{
    struct termios newtio, oldtio;

    if (tcgetattr(fd, &oldtio) != 0) {
        perror("GetupSerial err!\n");
        return -1;
    }

    bzero(&newtio, sizeof(newtio));

    newtio.c_lflag &= ~ECHO;
    cfsetispeed(&newtio, BAUDRATE);
    cfsetospeed(&newtio, BAUDRATE);

    newtio.c_cflag |= CLOCAL | CREAD;
    newtio.c_cflag &= ~CSIZE;
    newtio.c_cflag |= CS8;
    newtio.c_cflag &= ~PARENB;

    newtio.c_cflag &= ~CSTOPB;

    newtio.c_cc[VTIME] = 0;
    newtio.c_cc[VMIN] = 0;
    tcflush(fd, TCIFLUSH);

    if ((tcsetattr(fd, TCSANOW, &newtio)) != 0) {
        perror("com set error");
        return -1;
    }

    return 0;
}

int ClosePcUart(int fd)
{
    close(fd);

    return 0;
}
#endif

//缓冲区大小
#define BUF_INPUT_SIZE    4 //2048
#define BUF_OUTPUT_SIZE   2048
#define EXIT_STR    "exit"
#define I_EXIT      "I exit.\r\n"
#define I_RECEIVE   "I receive.\r\n"

//打开串口
HANDLE OpenSerial(const char *com, //串口名称，如COM1，COM2
    int baud,       //波特率：常用取值：CBR_9600、CBR_19200、CBR_38400、CBR_115200、CBR_230400、CBR_460800
    int byteSize,   //数位大小：可取值7、8；
    int parity,     //校验方式：可取值NOPARITY、ODDPARITY、EVENPARITY、MARKPARITY、SPACEPARITY
    int stopBits)   //停止位：ONESTOPBIT、ONE5STOPBITS、TWOSTOPBITS；
{    
    DCB dcb;
    BOOL b = FALSE;
	COMMTIMEOUTS CommTimeouts;	
    HANDLE comHandle = INVALID_HANDLE_VALUE;

    //打开串口
	comHandle = CreateFile(com,            //串口名称
		GENERIC_READ | GENERIC_WRITE,      //可读、可写   				 
		0, //FILE_SHARE_WRITE | FILE_SHARE_READ, //0,            // No Sharing                               
		NULL,         // No Security                              
		OPEN_EXISTING,// Open existing port only                     
		FILE_ATTRIBUTE_NORMAL,            // Non Overlapped I/O                           
		NULL);        // Null for Comm Devices

	if (INVALID_HANDLE_VALUE == comHandle) {
        printf("CreateFile fail(%d)\r\n", GetLastError());
        return comHandle;
    }

    // 设置读写缓存大小
	b = SetupComm(comHandle, BUF_INPUT_SIZE, BUF_OUTPUT_SIZE);
    if (!b) {
        printf("SetupComm fail\r\n");
    }

    //设定读写超时
	CommTimeouts.ReadIntervalTimeout = MAXDWORD;//读间隔超时
	CommTimeouts.ReadTotalTimeoutMultiplier = 0;//读时间系数
	CommTimeouts.ReadTotalTimeoutConstant = 0;//读时间常量
	CommTimeouts.WriteTotalTimeoutMultiplier = 1;//写时间系数
	CommTimeouts.WriteTotalTimeoutConstant = 1;//写时间常量
	b = SetCommTimeouts(comHandle, &CommTimeouts); //设置超时
    if (!b) {
        printf("SetCommTimeouts fail\r\n");
    }

    //设置串口状态属性
    GetCommState(comHandle, &dcb);//获取当前
	dcb.BaudRate = baud; //波特率
	dcb.ByteSize = byteSize; //每个字节有位数
	dcb.Parity   = parity; //无奇偶校验位
	dcb.StopBits = 1; //一个停止位
	b = SetCommState(comHandle, &dcb);//设置
    if (!b) {
        printf("SetCommState fail\r\n");
    }

    GetCommState(comHandle, &dcb);
    printf("baud:%d byteSize:%d parity:%d stopBits:%d\n", dcb.BaudRate, dcb.ByteSize, dcb.Parity, dcb.StopBits);

    return comHandle;
}

void CloseSerial(HANDLE comHandle)
{
    CloseHandle(comHandle);

    return;
}

int ReadBuf(HANDLE comHandle)
{
    BOOL bRet = FALSE;
    unsigned char buf[4];
    DWORD wRLen = 0;

    memset(buf, 0, sizeof(buf));
    bRet = ReadFile(comHandle, buf, 4, &wRLen, NULL);
    if (bRet == FALSE) {
        printf("ReadFile fail(%d)\r\n", GetLastError());
        return -1;
    } 

    usleep(50 * 1000);
    printf("==%#x %#x %#x %#x, datalen(%d)\n", buf[0], buf[1], buf[2], buf[3], wRLen);

    if (buf[1] == 0x05) {
        printf("XS5013 return successful buf!\r\n");
        return 0x02050003;
    } 
    
    if (buf[1] == 0x0A) {
        printf("XS5013 return failed buf!\r\n");
        return 0x020A0003;
    }

    if (buf[1] == 0x24) {
        printf("XS5013 start to notify...!\r\n");
        return 0x02240003;
    }

    if (wRLen == 0) {
        printf("XS5013 step to debug mode!\r\n");
        return 0x02140003;
    }

    return -1;
}

int WriteBuf(HANDLE comHandle, unsigned char *buf, int dataLen)
{
    DWORD wWLen = 0;
    BOOL bRet = FALSE;
    
    bRet = WriteFile(comHandle, buf, dataLen, &wWLen, NULL);
    if (bRet == FALSE) {
        printf("WriteFile fail(%d)\r\n", GetLastError());
        return -1;
    }
    
    usleep(50 * 1000);

    return 0;
}

int SendDebugCmd(HANDLE comHandle)
{
    int ret;
    int dataLen = 4;
    unsigned char buf[4] = {0x02, 0x14, 0x00, 0x03};

    ret = ReadBuf(comHandle);
    if (ret != 0x02240003) {
        printf("xs5013 status fail(%#x)\r\n", ret);
        return ret;
    }

    // 需要清空串口缓存，否者会导致获取上来的数据不对
    FlushFileBuffers(comHandle);
    PurgeComm(comHandle, PURGE_RXABORT);
    PurgeComm(comHandle, PURGE_RXCLEAR);

    ret = WriteBuf(comHandle, buf, dataLen);
    if (ret == -1) {
        return ret;
    }

    ret = ReadBuf(comHandle);
    if (ret != 0x02140003) {
        printf("SendDebugCmd fail(%#x)\r\n", ret);
        return ret;
    }

    return 0;
}

int int2bytes(int data, unsigned char *buf)
{
    if (buf == NULL) {
        printf("Data buf is null!\n");
        return -1;
    }

    buf[0] = (data >> 24) & 0xff;
    buf[1] = (data >> 16) & 0xff;
    buf[2] = (data >> 8) & 0xff;
    buf[3] = data & 0xff;

    return 0;
}

int CalChecksum(char *extBuf, int dataLen)
{
    int checksum = 0;

    if (extBuf == NULL) {
        printf("Data extBuf is null!\n");
        return -1;
    }

    for (int i = 0; i < dataLen; i++) {
        checksum += extBuf[i];
        checksum = checksum & 0xff;
    }

    return checksum;
}

int GetSendBuf()
{
    //send buf是由命令、地址、数据4字节的个数、数据组成
    return 0;
}

#define SEND_BUF_CMD_LEN    (0x04)  
#define SEND_BUF_ADDR_LEN   (0x04)
#define SEND_BUF_COUNT_LEN  (0x04)
#define SEND_BUF_DATA_LEN   (4 * 0x50)  //需要是4的倍数

int SendData(HANDLE comHandle)
{
    int ret;
    //char *dataTemp = ahdData;
    int baseAddr = 0x00010000;
    unsigned char buf[SEND_BUF_CMD_LEN + SEND_BUF_ADDR_LEN + SEND_BUF_COUNT_LEN + SEND_BUF_DATA_LEN] = {0x02, 0x18, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
    char *extBuf = NULL;
    int dataPos = 0;
    int dataLen = 0;
    int count = 0;

    FlushFileBuffers(comHandle);
    PurgeComm(comHandle, PURGE_RXABORT);
    PurgeComm(comHandle, PURGE_RXCLEAR);

    while (dataPos < sizeof(ahdData)) {

        int2bytes(baseAddr + dataPos, &buf[SEND_BUF_CMD_LEN]);  //地址;

        if ((sizeof(ahdData) - dataPos) < SEND_BUF_DATA_LEN) {
            memcpy(&buf[SEND_BUF_CMD_LEN + SEND_BUF_ADDR_LEN + SEND_BUF_COUNT_LEN], ahdData + dataPos, (sizeof(ahdData) - dataPos));
            count = (sizeof(ahdData) - dataPos) / 4;
            dataLen = SEND_BUF_CMD_LEN + SEND_BUF_ADDR_LEN + SEND_BUF_COUNT_LEN + (sizeof(ahdData) - dataPos);
            dataPos += (sizeof(ahdData) - dataPos);
        } else {
            memcpy(&buf[SEND_BUF_CMD_LEN + SEND_BUF_ADDR_LEN + SEND_BUF_COUNT_LEN], ahdData + dataPos, SEND_BUF_DATA_LEN);
            count = SEND_BUF_DATA_LEN / 4;
            dataLen = SEND_BUF_CMD_LEN + SEND_BUF_ADDR_LEN + SEND_BUF_COUNT_LEN + SEND_BUF_DATA_LEN;
            dataPos += SEND_BUF_DATA_LEN;
        }

        int2bytes(count, &buf[SEND_BUF_CMD_LEN + SEND_BUF_ADDR_LEN]);  //count;

        buf[2] = CalChecksum(&buf[SEND_BUF_CMD_LEN], dataLen - SEND_BUF_CMD_LEN);

        ret = WriteBuf(comHandle, buf, dataLen);
        if (ret != 0) {
            return -1;
        }
    }

    ret = ReadBuf(comHandle);
    if (ret != 0x02050003) {
        printf("SendData fail(%#x)\r\n", ret);
        return ret;
    }

    return 0;
}

int SendStartCmd(HANDLE comHandle)
{
    int ret;
    int dataLen = 8;
    unsigned char cmdBuf[8] = {0x02, 0x1b, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00};

    FlushFileBuffers(comHandle);
    PurgeComm(comHandle, PURGE_RXABORT);
    PurgeComm(comHandle, PURGE_RXCLEAR);

    ret = WriteBuf(comHandle, cmdBuf, dataLen);
    if (ret != 0) {
        return -1;
    }

    ret = ReadBuf(comHandle);
    if (ret != 0x02050003) {
        printf("Send start cmd fail(%#x)\r\n", ret);
        return ret;
    } 

    return 0;
}

int main()
{
    int ret;
    HANDLE comHandle = INVALID_HANDLE_VALUE;//串口句柄    	

    //打开串口
    const char *com = "COM8";
	comHandle = OpenSerial(com, CBR_115200, 8, NOPARITY, ONESTOPBIT);
	if (INVALID_HANDLE_VALUE == comHandle) {
		printf("OpenSerial %s fail!\r\n", com);
		return -1;
	} else {
	    printf("Open %s Successfully!\r\n", com);
    }
    
    usleep(500 * 1000);

    ret = ReadBuf(comHandle);
    if (ret != 0x02240003) {
        printf("xs5013 status err!\r\n");
        goto EXIT;
    }

    ret = SendDebugCmd(comHandle);
    if (ret != 0) {
        printf("xs5013 send debug cmd err(%#x)!\r\n", ret);
        goto EXIT;
    }

    ret = SendData(comHandle);
    if (ret != 0) {
        printf("xs5013 send data err!\r\n");
        goto EXIT;
    }

    ret = SendStartCmd(comHandle);
    if (ret != 0) {
        printf("xs5013 SendStartCmd err(%#x)!\r\n", ret);
    }

EXIT:
    printf("xs5013 OK!\r\n");
    getchar();

    CloseSerial(comHandle);
    return 0;
}
